package com.sn.socket.utils;






import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/*
 * 基于TCP协议的Socket通信，实现用户登陆
 * 服务器端
 */

public class SockServer extends ServerSocket {
    //记录客户端的数量
    private static int count = 0;
    private static final int SERVER_PORT = 9008;

    public static Hashtable<String, ClientTask> clientTalbles = new Hashtable<>(200);
    private static final Logger logger = LoggerFactory.getLogger(ServerSocket.class);

    public static void main(String[] args) throws IOException {
        logger.info("-----------------------start sockserver----------------------");
        new SockServer();//启动服务端
    }

    /**
     * 创建服务端Socket,创建向客户端发送消息线程,监听客户端请求并处理
     */
    public SockServer() throws IOException {
        super(SERVER_PORT);//创建ServerSocket
//        new PrintOutThread();//创建向客户端发送消息线程
        try {
            while (true) {//监听客户端请求，启个线程处理
                Socket socket = accept();
                ServerThread serverThread = new ServerThread(socket);
                serverThread.start();
                count++;//统计客户端的数量
                logger.info("客户端的数量：" + count);
            }
        } catch (Exception e) {
//             System.out.println("main exception:" + e.getMessage());
            logger.info("main exception:" + e.getMessage());
        } finally {
            close();
        }
    }

    public static void clientReset(String clientid) {
        //TODO: wanghui  断开连接要处理的事情
        logger.info("client " + clientid + " conn reset, client count" + --count);
        clientTalbles.remove(clientid);


    }


    /*
     * 服务器线程处理类
     */
    public class ServerThread extends Thread {
        // 和本线程相关的Socket
        Socket client = null;
        //879,887,899,909,914,934,940,947,959,972,977,981,990,1001,1003,1009,1017,1025,1027,1037,1051,1057,1065,1067,1072,1077,962,887,1025,955
        private String[] freqs = {"879", "887", "899", "909", "914", "934", "940", "947", "955", "959", "962", "972", "977", "981", "990", "1001", "1003", "1009", "1017", "1025", "1027", "1037", "1051", "1057", "1065", "1067", "1072", "1077"};
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        PrintWriter pw = null;
        private LinkedBlockingQueue<String> reportFreqs;
        private ClientTask clientTask ;
        private Thread sendMessageThread;
        private Thread autoWorkThread;

        public ServerThread(Socket socket) {
            this.client = socket;
            InetAddress address = socket.getInetAddress();
            logger.info("当前客户端的IP：" + address.getHostAddress() + " port:" + socket.getPort());
            reportFreqs = new LinkedBlockingQueue<String>(100);
        }

        //线程执行的操作，响应客户端的请求
        public void run() {
            try {
                //获取输入流，并读取客户端信息
                is = client.getInputStream();
                isr = new InputStreamReader(is);
                br = new BufferedReader(isr);
                pw = new PrintWriter(client.getOutputStream(), true);
                startSendThread();
                startAutoWork();
                String info = null;
                while ((info = br.readLine()) != null) {//循环读取客户端的信息
                    logger.info("accept message:" + info);
                    dealMessage(info);
                }
//                client.shutdownInput();//关闭输入流
            } catch (IOException e) {
                logger.info("exception:" + e.getMessage());
                if ("Connection reset".equals(e.getMessage())) {
                    SockServer.clientReset(client.getInetAddress().toString() + ":" + client.getPort());
                    close();
                }
            } finally {
                close();
            }
        }

        private void startSendThread() {
            sendMessageThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (client != null && client.isConnected() && !client.isClosed()) {
                        if (clientTask == null || clientTask.getSendMessages() == null || clientTask.getSendMessages().isEmpty()) {
                            continue;
                        }
                        String message;
                        while (!clientTask.getSendMessages().isEmpty()) {
                            message = clientTask.pollMessage();
                            try {
                                long second = message != null && message.split("#").length > 2 ?
                                        Long.valueOf(message.split("#")[2]) : 0;
                                sendMessage(message);
                                sleep(second);
                            } catch (InterruptedException e) {
                                logger.error("发送消息失败！！！！");
                            }
                        }
                    }
                }
            });
            sendMessageThread.start();
        }

        /**
         * 周期任务指令
         */
        private void startAutoWork() {
            autoWorkThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (client != null && client.isConnected() && !client.isClosed()) {
                        try {
                            long periodsleep = 0;
                            if (reportFreqs == null || reportFreqs.isEmpty()) {
                                sendMessage(FmTask.CMD_FM_SCAN + "#870-1080#0");
                                sleep((FmTask.scanSeconds+2) * 1000);
                                periodsleep += FmTask.scanSeconds+2;
                            }
                            while (!reportFreqs.isEmpty()) {
                                long time = recordingFreqs(reportFreqs.poll());
//                                sleep((time + 1) * 1000);
                                periodsleep += (time + 1);
                            }
                            reportFreqs.clear();
                            periodsleep = (periodsleep < 1800 && periodsleep > 90) ? (30 * 60 * 1000 - periodsleep * 1000) : 60000;
//                            sleep(periodsleep);
                            sleep(60000);
                        } catch (InterruptedException e) {
                            logger.error("下达周期任务指令错误！！！");
                        }
                    }
                }
            });
            autoWorkThread.start();
        }

        private void close() {
            //关闭资源
            try {
                if (pw != null)
                    pw.close();
                if (os != null)
                    os.close();
                if (br != null)
                    br.close();
                if (isr != null)
                    isr.close();
                if (is != null)
                    is.close();
                if (client != null)
                    client.close();
            } catch (IOException e) {
                logger.error("close error:" + e.getMessage());
            }
        }

        /**
         * 放入消息队列末尾，准备发送给客户端
         * 参数格式：comand#freq#seconds  ex:scanfreqs#87-108#60
         * @param msg
         */
        public void addMessage(String msg) {
            logger.info("add message:" + this.clientTask.getDeviceId()+ " to " + msg);
            String[] msgs = msg.split("#");
            long time = 0;
            try {
                time = Long.parseLong(msgs[2]);
            } catch (Exception e) {
                logger.error("addMessage error:" + e.getMessage());
            }
            this.clientTask.offer(msg);
        }

        /**
         * 放入消息队列头部，作为第一条指令，准备发送给客户端
         * 参数格式：comand#freq#seconds  ex:scanfreqs#87-108#60
         * @param msg
         */
        public void addFirstMessage(String msg) {
            logger.info("add first message:" + this.clientTask.getDeviceId()+ " to " + msg);
            String[] msgs = msg.split("#");
            long time = 0;
            try {
                time = Long.parseLong(msgs[2]);
            } catch (Exception e) {
                logger.error("addMessage error:" + e.getMessage());
            }
            this.clientTask.offerFirst(msg);
        }


        //向客户端发送一条消息
        public void sendMessage(String msg) {
            if (msg == null || "null".equals(msg))
                return;
            pw.println(msg);
            if (this.clientTask != null ) {
                logger.info("send to " + this.clientTask.getDeviceId() + " message as:" + msg);
            }
        }


        /**
         * parse the client message and return replymessge
         * 指令格式:deviceid#command#data, {设备ID}#{指令}#{数据}
         * @param message
         * @return String replymessage
         */
        public void dealMessage(String message) {
            String[] msgcontent = message.split("@");
            String regex = "1[0-9]{14}";
            if (!msgcontent[0].matches(regex) || msgcontent.length < 2) {
                logger.info("this message is invalid");
                return;
            }
            if (!clientTalbles.containsKey(msgcontent[0])) {
                clientTalbles.put(msgcontent[0],new ClientTask());
            }
            this.clientTask = clientTalbles.get(msgcontent[0]);
            if (clientTask.getDeviceId() == null) {
                this.clientTask.setDeviceId(msgcontent[0]);
            }
            this.clientTask.setIpAddreass(this.client.getInetAddress().getHostAddress());

            switch (msgcontent[1]) {  //TODO: wanghui 接收到客户端发送的消息进行处理
                case "scanfreqs":
                    freqs = msgcontent[2].split("#");
                    for (String s : freqs) {
                        if (s.length() < 3) {
                            continue;
                        }
                        reportFreqs.offer(s);
                    }
                    break;
                case "tune":
                    break;
                case "recording":
                    break;
                case "startreport":
                    break;
                case "devicereport":
                    break;
                default:
                    break;
            }
        }

        private long recordingFreqs(String freq) {
            long sleeptime = 0;
            if (freq == null || "null".equals(freq)) {
//                addMessage(FmTask.CMD_FM_SCAN + "#870-1080#0");
                return sleeptime;
            }
            if (!clientTask.getFreqsHashMap().containsKey(freq)) {
                clientTask.getFreqsHashMap().put(freq, new AtomicInteger(0));
            }
            long recordPreTimes = 1;
            if (FmTask.whitelistStr.indexOf(String.valueOf(freq)) != -1) {
                recordPreTimes = FmTask.whiteFreqRecordTimes;
            } else {
                if (FmTask.graylistStr.indexOf(String.valueOf(freq)) != -1) {
                    recordPreTimes = FmTask.grayFreqRecordTimes;
                }
            }
            if (clientTask.getFreqsHashMap().get(String.valueOf(freq)).longValue() % recordPreTimes == 0) {
                //录音  || 调频     //ex: scanfreqs#870-1080#0  | recording#879#30  # tune#879#0
                addMessage(FmTask.CMD_FM_RECORD + '#' + freq + "#" + FmTask.recordSeconds);
                sleeptime = FmTask.recordSeconds+2;
            } else {
                addMessage(FmTask.CMD_FM_TUNE + '#' + freq + "#2");
                sleeptime = 2;
            }
            clientTask.incrementTimes(freq);
            return sleeptime;
        }


    }


}